package com.minyue.sqlsession;

import com.minyue.config.BoundSql;
import com.minyue.pojo.Configuration;
import com.minyue.pojo.MappedStatement;
import com.minyue.utils.GenericTokenParser;
import com.minyue.utils.ParameterMapping;
import com.minyue.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ：minyue
 * @date ：Created in 2021/7/23 12:00 上午
 * @description：sql处理器实现类
 */

public class SimpleExecutor implements Executor {

    private Connection connection = null;


    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws Exception {
        //获取预编译对象
        PreparedStatement preparedStatement = getPreparedStatement(configuration, mappedStatement, params == null ? null : params[0]);
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = mappedStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        ArrayList<Object> results = new ArrayList<>();
        while (resultSet.next()) {
            //获取元数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            Object o = resultTypeClass.newInstance();
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                //属性名
                String columnName = metaData.getColumnName(i);
                //属性值
                Object value = resultSet.getObject(columnName);
                //创建属性描述器，为属性生成读写方法
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                //获取写方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //向类中写入值
                writeMethod.invoke(o, value);
            }
            results.add(o);
        }

        return (List<E>) results;
    }

    private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object... param) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //获取连接
        connection = configuration.getDataSource().getConnection();
        //对sql进行处理
        String sql = mappedStatement.getSqlText();
        BoundSql boundSql = getBoundSql(sql);
        String paramterType = mappedStatement.getParamterType();
        Class<?> paramterTypeClass = getClassType(paramterType);
        //获取预编译对象
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        if (param == null) {
            return preparedStatement;
        }
        return setParam(boundSql, paramterTypeClass, preparedStatement, param);
    }

    /**
     * 如果参数不为空，给参数赋值
     *
     * @param boundSql
     * @param paramterTypeClass
     * @param preparedStatement
     * @param param
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     * @throws SQLException
     */
    private PreparedStatement setParam(BoundSql boundSql, Class<?> paramterTypeClass, PreparedStatement preparedStatement, Object[] param) throws NoSuchFieldException, IllegalAccessException, SQLException {
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            Object o;
            if (param[0] instanceof Integer) {
                o = param[0];
            } else {
                ParameterMapping parameterMapping = parameterMappingList.get(i);
                String content = parameterMapping.getContent();
                Field declaredField = paramterTypeClass.getDeclaredField(content);
                declaredField.setAccessible(true);
                o = declaredField.get(param[0]);
            }

            //给占位符赋值
            preparedStatement.setObject(i + 1, o);
        }
        return preparedStatement;
    }

    @Override
    public void close() throws SQLException {
        connection.close();
    }

    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object[] param) throws Exception {
        PreparedStatement preparedStatement = getPreparedStatement(configuration, mappedStatement, param[0]);
        return preparedStatement.executeUpdate();
    }

    public Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        if (paramterType == null) {
            return null;
        }
        return Class.forName(paramterType);
    }

    public BoundSql getBoundSql(String sql) {
        //标记处理类:主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解 析工作，其中TokenHandler主要完成处理
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        //GenericTokenParser :通用的标记解析器，完成了代码片段中的占位符的解析，然后再根 据给定的标记处理器(TokenHandler)来进行表达式的处理
        //三个参数:分别为openToken (开始标记)、closeToken (结束标记)、handler (标记处理器)
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        String parse = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        return new BoundSql(parse, parameterMappings);
    }


}
